/**
 * 
 */
package com.fbty.mt.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.UnknownHostException;

import net.sf.json.JSONObject;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;

import com.fbty.mt.domain.AccountInfo;
import com.fbty.mt.domain.CheckInfo;
import com.fbty.mt.service.ProxyService;
import com.fbty.mt.socks.Proxy;
import com.fbty.mt.socks.Socks5Proxy;
import com.fbty.mt.socks.SocksException;
import com.fbty.mt.socks.SocksSocket;
import com.fbty.mt.socks.UserPasswordAuthentication;

/**
 * @author freedom
 *
 */
public class ProxyServiceImpl implements ProxyService{
	
	private static final int CONNECTION_TIMEOUT = 100000;// 连接超时时间
	private static final int SO_TIMEOUT = 100000;// socket 超时时间 接收数据时所等待的时间
	
	private  String accountHost = "http://192.168.1.107:8080/proxy/proxyServlet";
	
	private String host; //用于验证代理是否可以用的地址，一般用大型网站比较好，比如 www.google.com 或者www.163.com
	
	private int port; //端口
	
	public void setHost(String host) {
		this.host = host;
	}

	public void setPort(int port) {
		this.port = port;
	}

	@Override
	public CheckInfo checkConnection(String proxyHost, int proxyPort, int proxyType) {
		
		switch (proxyType) {
		
			case CheckInfo.SOCKS4_PROXY:
				return checkS4Proxy(proxyHost, proxyPort, null);
			case CheckInfo.HTTP_PROXY:
				return checkHttpProxy(proxyHost, proxyPort,null,null);
			case CheckInfo.SOCKS5_PROXY:
				return checkS5Proxy(proxyHost,proxyPort,null,null);
			default:
				break;
		}
		
		
		return null;
	}
	
	/**
	 * 检测有帐号密码的S5代理的联通性，一般共享IP是不用输帐号密码的，独享IP需要
	 * @param proxyHost 代理地址 
	 * @param proxyPort 代理端口
	 * @param proxyUser 代理帐号，独享IP用
	 * @param proxyPassword 代理密码，独享IP用
	 * @return 检测结果
	 */
	public CheckInfo checkS5Proxy(String proxyHost, int proxyPort,String proxyUser,String proxyPassword){
		
		if(host==null){
			host = "www.google.com";
		}
		
		if(port==0){
			port=80;
		}
		
		CheckInfo info = new CheckInfo();
		info.setHost(proxyHost);
		info.setPort(proxyPort);
		int result = 0;
		try {

			String request  ="GET / HTTP/1.1\r\nHost: "+host+":"+port+"\r\n\r\n";
			// Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001");
			Proxy.setDefaultProxy(proxyHost, proxyPort);
			if(proxyUser!=null&& proxyPassword!=null){
				UserPasswordAuthentication upa = new UserPasswordAuthentication(proxyUser, proxyPassword);
				Socks5Proxy proxy = (Socks5Proxy) Proxy.getDefaultProxy();
				proxy.setAuthenticationMethod(upa.METHOD_ID, upa);
			}
			SocksSocket s = new SocksSocket(host, port);
			info.setDelay(s.getDelay());
			OutputStream out = s.getOutputStream();
			InputStream in = s.getInputStream();
			out.write(request.getBytes());
			out.flush();
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			String str;
			while ((str = reader.readLine()) != null) {
				if(str.indexOf("HTTP/1.0")!=-1||str.indexOf("HTTP/1.1")!=-1){
					break;
				}
			}
			out.close();
			in.close();

		} catch (SocksException sock_ex) {
			// Usually it will turn in more or less meaningfull message
			System.err.println("SocksException:" +proxyHost+":"+proxyPort+"\n"+ sock_ex);
			result = sock_ex.getErrorCode();
			//sock_ex.printStackTrace();
		} catch (UnknownHostException e) {
			//e.printStackTrace();
			result = CheckInfo.UNKNOWN_EXCEPTION;
		} catch (IOException e) {
			result = CheckInfo.PROXY_CHECK_FAILURE;
			//e.printStackTrace();
		}
		
		info.setReslut(result);
		info.setCheckType(CheckInfo.SOCKS5_PROXY);
		return info;
	}
	
	
	/**
	 * S4代理检测
	 * @param proxyHost 代理地址
	 * @param proxyPort 代理端口
	 * @param user 一般都是空，少数s4有帐号
	 * @return
	 */
	public CheckInfo checkS4Proxy(String proxyHost, int proxyPort,String user){
		
		if(host==null){
			host = "www.google.com";
		}
		
		if(port==0){
			port=80;
		}
		
		CheckInfo info = new CheckInfo();
		info.setHost(proxyHost);
		info.setPort(proxyPort);
		int result = 0;
		try {

			String request  ="GET / HTTP/1.1\r\nHost: "+host+":"+port+"\r\n\r\n";

			Proxy.setDefaultProxy(proxyHost, proxyPort,user);
			SocksSocket s = new SocksSocket(host, port);
			info.setDelay(s.getDelay());
			OutputStream out = s.getOutputStream();
			InputStream in = s.getInputStream();
			out.write(request.getBytes());
			out.flush();
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			String str;
			while ((str = reader.readLine()) != null) {
				if(str.indexOf("HTTP/1.0")!=-1||str.indexOf("HTTP/1.1")!=-1){
					break;
				}
				
				if(str.indexOf("HTTP/1.1")!=-1){
					break;
				}
			}
			out.close();
			in.close();

		} catch (SocksException sock_ex) {
			// Usually it will turn in more or less meaningfull message
			System.err.println("SocksException:" + sock_ex);
			result = sock_ex.getErrorCode();
		} catch (UnknownHostException e) {
			e.printStackTrace();
			result = CheckInfo.UNKNOWN_EXCEPTION;
		} catch (IOException e) {
			result = CheckInfo.PROXY_CHECK_FAILURE;
			e.printStackTrace();
		}
		
		info.setReslut(result);
		info.setCheckType(CheckInfo.SOCKS5_PROXY);
		return info;
	}
	
	
	/**
	 * HTTP 代理验证
	 * @param proxyHost 
	 * @param proxyPort
	 * @param userName
	 * @param password
	 * @return
	 */
	public CheckInfo checkHttpProxy(String proxyHost, int proxyPort, String userName, String password){
		
		if(host==null){
			host = "www.google.com";
		}
		
		if(port==0){
			port = 80;
		}
		
		CheckInfo info = new CheckInfo();
		info.setHost(proxyHost);
		info.setPort(proxyPort);
		info.setCheckType(CheckInfo.HTTP_PROXY);
		
		HttpClient httpClient = new HttpClient();
		// 设置超时时间
		httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(CONNECTION_TIMEOUT);
		
		GetMethod get = new GetMethod("http://"+proxyHost+":"+proxyPort+"/");
		//设置请求超时时间
		get.getParams().setSoTimeout(SO_TIMEOUT);
		try {
			long start = System.currentTimeMillis();
			httpClient.executeMethod(get);
			long end = System.currentTimeMillis();
			if(get.getStatusLine()!=null){
				//写这么多的P话就为了计算这个延迟
				info.setDelay(end-start);
			}
			
		} catch (HttpException e1) {
			info.setReslut(CheckInfo.PROXY_NO_CONNECT);
			e1.printStackTrace();
		} catch (IOException e1) {
			info.setReslut(CheckInfo.PROXY_IO_ERROR);
			e1.printStackTrace();
		}finally {
			//用一次必须调用一次此方法
        	get.releaseConnection();
        }
		
		
		
		//设置代理端口
        httpClient.getHostConfiguration().setProxy(proxyHost, proxyPort);
        if(userName!=null&&password!=null){
        	UsernamePasswordCredentials creds = new UsernamePasswordCredentials(userName, password);
        	httpClient.getState().setProxyCredentials(AuthScope.ANY, creds);
        }
        String url = "http://"+host+":"+port+"/";
        GetMethod httpget = new GetMethod(url);
        try { 
        	
        	//long start = System.currentTimeMillis();
        	httpClient.executeMethod(httpget);
        	//long end = System.currentTimeMillis();
        	int status = httpget.getStatusLine().getStatusCode();
        	if(status==200){
        		info.setReslut(CheckInfo.PROXY_CHECK_SUCCESS);
        		//info.setDelay(end-start);
        		//String body = httpget.getResponseBodyAsString();
        	}else if(status==407){
        		info.setReslut(CheckInfo.PROXY_AUTH_FAILURE);
        	}
        } catch (HttpException e) {
        	info.setReslut(CheckInfo.PROXY_CHECK_FAILURE);
			e.printStackTrace();
		} catch (IOException e) {
			info.setReslut(CheckInfo.PROXY_IO_ERROR);
			e.printStackTrace();
		} finally {
        	httpget.releaseConnection();
        }
		
		return info;
		
	}
	
	@Override
	public CheckInfo checkConnection(String proxyHost, int proxyPort, String proxyUser,String proxyPassword) {
		return checkS5Proxy(proxyHost, proxyPort, proxyUser, proxyPassword);
	}
	
	
	@Override
	public AccountInfo creatAccount(String username, String password,String disabledate, String disabletime, String host, int port) {
		
		
		HttpClient httpClient = new HttpClient();
		// 设置超时时间
		httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(CONNECTION_TIMEOUT);
		httpClient.getHttpConnectionManager().getParams().setSoTimeout(SO_TIMEOUT);
		PostMethod post = new PostMethod(accountHost);
		
		
		post.addParameter(new NameValuePair("user",username));
		post.addParameter(new NameValuePair("password",password));
		post.addParameter(new NameValuePair("disabledate",disabledate));
		post.addParameter(new NameValuePair("disabletime",disabletime));
		post.addParameter(new NameValuePair("host",host));
		post.addParameter(new NameValuePair("port",String.valueOf(port)));
		
		try {
			httpClient.executeMethod(post);
			int status = post.getStatusLine().getStatusCode();
        	if(status==200){
        		
        		InputStream in = post.getResponseBodyAsStream();
        		BufferedReader reader = new BufferedReader(new InputStreamReader(in, "utf-8"));
        		String str;
        		StringBuilder json = new StringBuilder();
        		while((str=reader.readLine())!=null){
        			json.append(str);
        		}
        		JSONObject jsonObject = JSONObject.fromObject(json.toString());
        		AccountInfo info = (AccountInfo) JSONObject.toBean(jsonObject, AccountInfo.class);
        		return info;
        	}else{
        		return null;
        	}
			
		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
		return null;
	}
	
	public void setAccountHost(String accountHost) {
		this.accountHost = accountHost;
	}
	
	public AccountInfo creatAccount(String username, String password){
		return null;
	}
	
	public static void main(String[] args) {
		
		ProxyServiceImpl proxy = new ProxyServiceImpl();
		AccountInfo info = proxy.creatAccount("test", "123", "2013-12-01", "09:01:11", "41.141.249.197", 3389);
		System.out.println(info.getResult());
	}
}
